package corpus;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;



import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.ISenseEntry;
import edu.mit.jwi.item.ISenseKey;
import edu.mit.jwi.item.ISynset;
import edu.mit.jwi.item.ISynsetID;
import edu.mit.jwi.item.IWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;
import edu.mit.jwi.item.Pointer;

/**
 * This class provides glue for WordNet, it assumes you have WordNet installed.
 */
public class WordNet {
	private IDictionary dict;

	public WordNet(String wnhome) throws IOException {
		String path = wnhome + File.separator + "dict";
		URL url = new URL("file", null, path);

		// construct the dictionary object and open it
		dict = new Dictionary(url);
		dict.open();
	}

	/**
	 * @return all words in the dictionary
	 */
	public Set<Word> words() {
		Set<Word> words = new HashSet<Word>();
		Iterator<ISenseEntry> itr = dict.getSenseEntryIterator();
		while (itr.hasNext()) {
			ISenseEntry en = itr.next();
			ISenseKey key = en.getSenseKey();
			String lemma = key.getLemma();
			String pos = en.getPOS().name();
			Word w = new Word(lemma, pos);
			words.add(w);
		}
		return words;
	}

	/**
	 * Gives all the synonyms for a word.
	 */
	public Set<Word> synonyms(Word word) {
		Set<Word> set = new HashSet<Word>();
		IIndexWord idxWord = dict.getIndexWord(word.getLemma(),
				POS.valueOf(word.getPos()));
		List<IWordID> wordIDs = idxWord.getWordIDs();
		for (IWordID wordID : wordIDs) {
			IWord iword = dict.getWord(wordID);
			ISynset synset = iword.getSynset();

			for (IWord w : synset.getWords()) {
				Word newWord = new Word(w.getLemma(), w.getPOS().name());
				set.add(newWord);
			}
		}
		return set;
	}
	
	/**
	 * Gives all the meronyms for a word.
	 * TODO
	 */
	public Set<Word> meronym(Word word) {
		return null;
	}


	/**
	 * Gives all synonyms, hypernyms of a word. Also the "similar to" set as
	 * defined by WordNet.
	 */
	public Set<Word> relatedWords(Word word) {
		Set<Word> set = new HashSet<Word>();
		IIndexWord idxWord = dict.getIndexWord(word.getLemma(),
				POS.valueOf(word.getPos()));
		List<IWordID> wordIDs = idxWord.getWordIDs();
		for (IWordID wordID : wordIDs) {
			IWord iword = dict.getWord(wordID);
			ISynset synset = iword.getSynset();

			List<ISynset> synsets = new ArrayList<ISynset>();
			synsets.add(synset);

			addSynsets(synset, synsets, Pointer.HYPONYM);
			addSynsets(synset, synsets, Pointer.SIMILAR_TO);
			addSynsets(synset, synsets, Pointer.HYPERNYM);

			for (ISynset syn : synsets) {
				for (IWord w : syn.getWords()) {
					Word newWord = new Word(w.getLemma(), w.getPOS().name());
					set.add(newWord);
				}
			}
		}
		return set;
	}

	private void addSynsets(ISynset synset, List<ISynset> synsets, Pointer p) {
		List<ISynsetID> hypoSynsetID = synset.getRelatedSynsets(p);
		for (ISynsetID id : hypoSynsetID)
			synsets.add(dict.getSynset(id));
	}

	/**
	 * length is defined as the minimum synonyms/hypernyms/meronyms we have to
	 * visit before we find w2 from w1.
	 * TODO
	 */
	public int length(Word w1, Word w2) {
		return 0;
	}
}
